/**
 * @file dial_switch.c
 *
 */

/*********************
 *      INCLUDES
 *********************/
#include "lv_watch.h"

#if USE_LV_WATCH_DIAL!= 0

#include <stdio.h>
#include <stdlib.h>

/*********************
 *      DEFINES
 *********************/

/**********************
 *      TYPEDEFS
 **********************/

/**********************
 *  STATIC PROTOTYPES
 **********************/
static void * dial_get_sub_img(watch_element_img_dsc_t * img_dsc, uint8_t index);
static void dial_update_bar(watch_element_base_t * base);
static void dial_element_setting_event_cb(lv_obj_t * obj, lv_event_t event);
static void dial_element_setting_btn_event_cb(lv_obj_t * obj, lv_event_t event);
static void dial_save_act_element(lv_point_t pos, uint8_t type);
static void dial_get_act_element(watch_element_t * element);
#if DIAL_USE_CANVAS
static lv_obj_t * dial_create_canvas(lv_obj_t * bg);
static void dial_create_canvas_text(char * txt, watch_element_label_dsc_t * dsc, lv_coord_t offset_x, lv_coord_t offset_y);
static bool dial_get_bg_switch(watch_dial_t * dial);
static bool dial_is_unchangeable_img(watch_img_type_t type);
static bool dial_is_unchangeable_label(watch_label_type_t type);
static void dial_get_element_pos(watch_element_type_t type, lv_point_t * pos);
static void dial_update_canvas_img(watch_element_base_t * base);
static void dial_update_canvas_label(watch_element_base_t * base);
static void dial_update_canvas(void * img_src, int16_t angle, lv_coord_t offset_x, lv_coord_t offset_y);
#else
static void dial_update_img(watch_element_base_t * base);
static void dial_update_label(watch_element_base_t * base);
#endif
/**********************
 *  STATIC VARIABLES
 **********************/
#if DIAL_USE_CANVAS
#define CANVAS_WIDTH  LV_HOR_RES
#define CANVAS_HEIGHT LV_VER_RES
#endif
static uint8_t g_bg_index = 0;
/**********************
 *      MACROS
 **********************/

/**********************
 *   GLOBAL FUNCTIONS
***********************/
void dial_reset_bg_index(void)
{
    g_bg_index = 0;
}

lv_obj_t * dial_add_bg_img(lv_obj_t * par, watch_dial_t * watch_dial)
{
    lv_obj_t * img = lv_img_create(par, NULL);
    if(NULL == img) return NULL;

    lv_obj_set_click(img, false);
    lv_img_set_src(img, watch_dial->bg_img);

    return img;
}

bool dial_add_element(lv_obj_t * par, watch_dial_t * watch_dial)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    watch_element_label_dsc_t * label_dsc;
    watch_element_img_dsc_t * img_dsc;
    lv_obj_t * bg;
#if DIAL_USE_CANVAS
    bg = dial_create_canvas(par);
#else
    bg = dial_add_bg_img(par, watch_dial);
#endif
    _LV_LL_READ(watch_dial->element_ll, element) {
        if(element->element_cnt > 1)
            dial_get_act_element(element);
        _LV_LL_READ(element->element_dsc_ll, base_node) {
            watch_element_base_t * base = (watch_element_base_t *)*base_node;
            if(base->element_type == element->act_type) {
                if(base->img_cnt > 0) {
                    lv_obj_t * img;
                    _LV_LL_READ(base->img_ll, img_dsc) {
#if DIAL_USE_CANVAS
                        if(img_dsc->img_type == IMG_TYPE_TIME_SEC_HAND || img_dsc->img_type == IMG_TYPE_TIME_SEC_TENS
                                || img_dsc->img_type == IMG_TYPE_TIME_SEC_UNIT)
#else
                        if(img_dsc->img_type == IMG_TYPE_BG)
                            img_dsc->img_obj = bg;
                        else
#endif
                        {
                            img = lv_img_create(bg, NULL);
                            lv_img_set_src(img, _lv_ll_get_head(&img_dsc->subimg->sub_img_ll));
                            lv_obj_set_click(img, false);
                            if(img_dsc->img_type == IMG_TYPE_TIME_HOUR_HAND || img_dsc->img_type == IMG_TYPE_TIME_MIN_HAND
                                    || img_dsc->img_type == IMG_TYPE_TIME_SEC_HAND || img_dsc->img_type == IMG_TYPE_WEEK_HAND) {
                                uint8_t pivot_x = lv_obj_get_width(img) / 2;
                                uint8_t pivot_y = lv_obj_get_height(img) / 2;
                                lv_img_set_pivot(img, pivot_x, pivot_y);
                            }
                            lv_obj_align(img, NULL, LV_ALIGN_IN_TOP_LEFT,
                                         element->element_pos.x + img_dsc->img_pos.x, element->element_pos.y + img_dsc->img_pos.y);
                            img_dsc->img_obj = img;
                        }
                    }
                }
                if(base->label_cnt > 0) {
                    _LV_LL_READ(base->label_ll, label_dsc) {
                        printf("%s, label_type:%d, ttf_file:%s\n", __FUNCTION__, label_dsc->label_type, label_dsc->ttf_file);
#ifdef USE_FONT_TTF
                        label_dsc->label_font = lv_mem_alloc(sizeof(lv_font_t));
                        if(strlen(label_dsc->ttf_file) > 0) {
                            if(lv_freetype_font_init(label_dsc->label_font, label_dsc->ttf_file, label_dsc->font_size) != 0) {
                                lv_mem_free(label_dsc->label_font);
                                label_dsc->label_font = NULL;
                                return false;
                            }
                        } else {
                            lv_freetype_font_init(label_dsc->label_font, LV_FONT_TTF, label_dsc->font_size);
                        }
#endif

#if DIAL_USE_CANVAS
                        if(dial_is_unchangeable_label(label_dsc->label_type))
                            dial_create_canvas_text(label_dsc->text, label_dsc, element->element_pos.x, element->element_pos.y);
                        if(label_dsc->label_type == LABEL_TYPE_TIME_SEC)
#endif
                        {
                            lv_obj_t * label;
                            label = lv_label_create(bg, NULL);
#ifdef USE_FONT_TTF
                            lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, label_dsc->label_font);
#else
                            if(label_dsc->font_size < 30)
                                lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font20);
                            else
                                lv_obj_add_style(label, LV_LABEL_PART_MAIN, &lv_watch_font30);
#endif
                            lv_label_set_text(label, label_dsc->text);
                            lv_obj_set_click(label, false);
                            lv_obj_align(label, NULL, LV_ALIGN_IN_TOP_LEFT,
                                         element->element_pos.x + label_dsc->text_pos.x, element->element_pos.y + label_dsc->text_pos.y);
                            lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, label_dsc->text_color);
                            lv_label_set_align(label, LV_LABEL_ALIGN_LEFT);
                            label_dsc->label_obj = label;
                        }
                    }
                }

                if(base->bar_dsc.bar_type != BAR_TYPE_INVALID) {
                    lv_obj_t * bar = NULL;
                    if(base->bar_dsc.bar_type == BAR_TYPE_RECT) {
                        bar = lv_bar_create(bg, NULL);
                        lv_obj_set_style_local_bg_color(bar, LV_BAR_PART_BG, LV_STATE_DEFAULT, base->bar_dsc.bar_color);
                    } else if(base->bar_dsc.bar_type == BAR_TYPE_CIRCLE) {
                        bar = lv_arc_create(bg, NULL);
                        lv_arc_set_bg_angles(bar, 0, 360);
                        lv_arc_set_angles(bar, 270, 270);
                        lv_obj_set_style_local_line_color(bar, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, base->bar_dsc.bar_color);
                        lv_obj_set_style_local_line_width(bar, LV_ARC_PART_INDIC, LV_STATE_DEFAULT, LV_DPX(10));
                        lv_obj_set_style_local_line_color(bar, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_COLOR_GRAY);
                        lv_obj_set_style_local_line_width(bar, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_DPX(10));
                        lv_obj_set_style_local_line_opa(bar, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_50);
                        lv_obj_set_style_local_bg_opa(bar, LV_ARC_PART_BG, LV_STATE_DEFAULT, LV_OPA_0);
                    }
                    lv_obj_set_size(bar, base->bar_dsc.bar_w, base->bar_dsc.bar_h);
                    lv_obj_align(bar, NULL, LV_ALIGN_IN_TOP_LEFT, element->element_pos.x + base->bar_dsc.bar_pos.x, element->element_pos.y + base->bar_dsc.bar_pos.y);
                    base->bar_dsc.bar_obj = bar;
                }
            }
        }
    }
    return true;
}

void dial_update_all_element(lv_obj_t * clock_cont)
{
    //update all element(except second if DIAL_USE_CANVAS)
    if(clock_cont == NULL) return;
    lv_clock_ext_t * clock_ext = (lv_clock_ext_t *)lv_obj_get_ext_attr(clock_cont);
    watch_dial_t * watch_dial = clock_ext->watch_dial;
    uint8_t i = 0;
    for(i = ELEMENT_TYPE_MAX - 2; i > ELEMENT_TYPE_INVILID; i--) {
        dial_update_element(watch_dial, i);
    }
}

void dial_update_element(watch_dial_t * watch_dial, watch_element_type_t type)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    _LV_LL_READ(watch_dial->element_ll, element) {
        if(element->act_type == type) {
            _LV_LL_READ(element->element_dsc_ll, base_node) {
                watch_element_base_t * base = (watch_element_base_t *)*base_node;
                if(base->element_type == type) {
                    if(base->img_cnt > 0) {
#if DIAL_USE_CANVAS
                        dial_update_canvas_img(base);
#else
                        dial_update_img(base);
#endif
                    }
                    if(base->label_cnt > 0) {
#if DIAL_USE_CANVAS
                        dial_update_canvas_label(base);
#else
                        dial_update_label(base);
#endif
                    }
                    if(base->bar_dsc.bar_type != BAR_TYPE_INVALID) {
                        dial_update_bar(base);
                    }
                }
            }
        }
    }
}

void dial_init_act_element(watch_dial_t * watch_dial)
{
    nv_watch_launcher_t dial_info;
    watch_element_t * element;
    uint8_t i = 0;
    UI_NV_Read_Req(NV_SECTION_UI_LAUNCHER, 0, sizeof(nv_watch_launcher_t), (uint8_t *)&dial_info);
    if(memcmp(dial_info.dial_name, watch_dial->name, WATCH_MAX_DIAL_NAME_LEN)) {
        memset(&dial_info.dial_name, 0, NV_DIAL_NAME_MAX_LEN);
        memset(&dial_info.element, 0, sizeof(nv_watch_dial_element_info) * NV_DIAL_MAX_ELEMENT_CNT);
        memcpy(dial_info.dial_name, watch_dial->name, NV_DIAL_NAME_MAX_LEN);
        _LV_LL_READ(watch_dial->element_ll, element) {
            if(element->element_cnt > 1 && i < NV_DIAL_MAX_ELEMENT_CNT) {
                dial_info.element[i].pos.x = element->element_pos.x;
                dial_info.element[i].pos.y = element->element_pos.y;
                dial_info.element[i].act_type = element->act_type;
                i++;
            }
        }
        UI_NV_Write_Req(NV_SECTION_UI_LAUNCHER, 0, sizeof(nv_watch_launcher_t), (uint8_t *)&dial_info);
    }
}

void dial_add_configurable_element(lv_obj_t * par)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    watch_element_base_t * base;
    lv_obj_t * element_img;
    watch_dial_t * dial = ((lv_clock_ext_t *)lv_obj_get_ext_attr(dial_get_clock_cont()))->watch_dial;
    _LV_LL_READ(dial->element_ll, element) {
        if(element->element_cnt > 1) {
            _LV_LL_READ(element->element_dsc_ll, base_node) {
                base = (watch_element_base_t *)*base_node;
                if(base->element_type == element->act_type) {
                    element_img = lv_img_create(par, NULL);
                    lv_obj_set_click(element_img, true);
                    lv_img_set_src(element_img, base->element_pre_img);
                    lv_obj_set_pos(element_img, element->element_pos.x, element->element_pos.y);
                    lv_obj_set_event_cb(element_img, dial_element_setting_event_cb);
                    lv_watch_set_free_ptr(element_img, element);
                }
            }
        }
    }
}

#if DIAL_USE_CANVAS != 0
/* ambient png from gui/lv_watch/resource/png/dial_default_ambient/am_digit_bg.png must include alpha, since canvas is TRUE_COLOR_ALPHA */
void dial_clean_canvas(bool switch_bg)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    watch_element_img_dsc_t * img_dsc;
    watch_element_label_dsc_t * label_dsc;
    lv_obj_t * cont = dial_get_clock_cont();
    if(cont == NULL) return;
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(cont);
    if(ext == NULL || ext->canvas == NULL) return;
    lv_img_dsc_t * dsc = lv_canvas_get_img(ext->canvas);
    lv_img_cache_entry_t * cdsc;
    //add unchangeable img
    if(dial_get_bg_switch(ext->watch_dial) == false) {
        cdsc = _lv_img_cache_open(ext->watch_dial->bg_img, LV_COLOR_WHITE);
        memcpy((uint8_t *)dsc->data, cdsc->dec_dsc.img_data, LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(CANVAS_WIDTH, CANVAS_HEIGHT));
        lv_img_cache_invalidate_src(ext->watch_dial->bg_img);
    }
    _LV_LL_READ(ext->watch_dial->element_ll, element) {
        if(element->element_cnt > 1) dial_get_act_element(element);
        _LV_LL_READ(element->element_dsc_ll, base_node) {
            watch_element_base_t * base = (watch_element_base_t *)*base_node;
            if(base->element_type == ELEMENT_TYPE_BG_SWITCH) {
                 _LV_LL_READ(base->img_ll, img_dsc) {
                     if(img_dsc->img_type == IMG_TYPE_BG) {
                         if(switch_bg) {
                             g_bg_index = g_bg_index + 1;
                             if(g_bg_index == img_dsc->subimg->sub_img_cnt)
                                 g_bg_index = 0;
                         }
                         void * sub_img = dial_get_sub_img(img_dsc, g_bg_index);
                         cdsc = _lv_img_cache_open(sub_img, LV_COLOR_WHITE);
                         memcpy((uint8_t *)dsc->data, cdsc->dec_dsc.img_data, LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(CANVAS_WIDTH, CANVAS_HEIGHT));
                         lv_img_cache_invalidate_src(sub_img);
                     }
                 }
            }
            if(base->element_type == element->act_type) {
                if(base->img_cnt > 0) {
                    _LV_LL_READ(base->img_ll, img_dsc) {
                        if(dial_is_unchangeable_img(img_dsc->img_type)) {
                            dial_update_canvas(_lv_ll_get_head(&img_dsc->subimg->sub_img_ll), 0,
                                               element->element_pos.x + img_dsc->img_pos.x, element->element_pos.y + img_dsc->img_pos.y);
                        }
                    }
                }
                if(base->label_cnt > 0) {
                    _LV_LL_READ(base->label_ll, label_dsc) {
                        if(dial_is_unchangeable_label(label_dsc->label_type)) {
                            dial_create_canvas_text(label_dsc->text, label_dsc, element->element_pos.x, element->element_pos.y);
                        }
                    }
                }
            }
        }
    }
}

void dial_update_second(uint8_t sec, watch_dial_t * watch_dial)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    watch_element_img_dsc_t * img_dsc;
    watch_element_label_dsc_t * label_dsc;
    void * sub_img = NULL;
    _LV_LL_READ(watch_dial->element_ll, element) {
        _LV_LL_READ(element->element_dsc_ll, base_node) {
            watch_element_base_t * base = (watch_element_base_t *)*base_node;
            if(base->element_type == element->act_type) {
                if(base->img_cnt > 0) {
                    _LV_LL_READ(base->img_ll, img_dsc) {
                        if(IMG_TYPE_TIME_SEC_HAND == img_dsc->img_type) {
                            int16_t angle = sec * 60;
                            if(angle < 0) angle += 3600;
                            lv_img_set_angle(img_dsc->img_obj, angle);
                        } else if(IMG_TYPE_TIME_SEC_TENS == img_dsc->img_type) {
                            sub_img = dial_get_sub_img(img_dsc, sec / 10);
                            if(sub_img)
                                lv_img_set_src(img_dsc->img_obj, sub_img);
                        } else if(IMG_TYPE_TIME_SEC_UNIT == img_dsc->img_type) {
                            sub_img = dial_get_sub_img(img_dsc, sec % 10);
                            if(sub_img)
                                lv_img_set_src(img_dsc->img_obj, sub_img);
                        }
                    }
                }
                if(base->label_cnt > 0) {
                    _LV_LL_READ(base->label_ll, label_dsc) {
                        if(LABEL_TYPE_TIME_SEC == label_dsc->label_type) {
                            char txt[4] = {0};
                            snprintf(txt, 4, "%.2d", sec);
                            lv_label_set_text(label_dsc->label_obj, txt);
                        }
                    }
                }
            }
        }
    }
}
#endif
/**********************
 *   STATIC FUNCTIONS
 **********************/
#if DIAL_USE_CANVAS != 0
static lv_obj_t * dial_create_canvas(lv_obj_t * bg)
{
    lv_obj_t * canvas = lv_canvas_create(bg, NULL);
    char * cbuf = lv_mem_alloc(LV_CANVAS_BUF_SIZE_TRUE_COLOR_ALPHA(CANVAS_WIDTH, CANVAS_HEIGHT));
    LV_ASSERT_MEM(cbuf);
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(dial_get_clock_cont());
    ext->canvas = canvas;
    lv_canvas_set_buffer(canvas, cbuf, CANVAS_WIDTH, CANVAS_HEIGHT, LV_IMG_CF_TRUE_COLOR_ALPHA);
    lv_obj_align(canvas, NULL, LV_ALIGN_CENTER, 0, 0);
    dial_clean_canvas(false);
    return canvas;

}

static void dial_update_canvas(void * img_src, int16_t angle, lv_coord_t offset_x, lv_coord_t offset_y)
{
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(dial_get_clock_cont());

    if(angle) {
        lv_img_cache_entry_t * cdsc = NULL;
        lv_img_dsc_t img;
        cdsc = _lv_img_cache_open(img_src, LV_COLOR_BLACK);
        if(cdsc == NULL)
            printf("%s: img path = %s \n", __FUNCTION__, (char *)img_src);
        LV_ASSERT_NULL(cdsc);
        memcpy(&img.header, &cdsc->dec_dsc.header, sizeof(lv_img_header_t));
        img.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
        img.data = cdsc->dec_dsc.img_data;
        lv_canvas_transform(ext->canvas, &img, angle, LV_IMG_ZOOM_NONE, offset_x, offset_y, img.header.w / 2, img.header.h / 2, true);
    } else {
        lv_draw_img_dsc_t draw_img_dsc;
        lv_draw_img_dsc_init(&draw_img_dsc);
        lv_canvas_draw_img(ext->canvas, offset_x, offset_y, img_src, &draw_img_dsc);
    }

    lv_img_cache_invalidate_src(img_src);
}

static void dial_create_canvas_text(char * txt, watch_element_label_dsc_t * dsc, lv_coord_t offset_x, lv_coord_t offset_y)
{
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(dial_get_clock_cont());
    lv_draw_label_dsc_t draw_dsc;
    lv_draw_label_dsc_init(&draw_dsc);
    draw_dsc.opa = LV_OPA_COVER;
    draw_dsc.color = dsc->text_color;
#ifdef USE_TTF_FONT
    draw_dsc.font = dsc->label_font;
#else
    if(dsc->font_size < 30)
        draw_dsc.font = LV_THEME_WATCH_NIGHT_FONT_20;
    else
        draw_dsc.font = LV_THEME_WATCH_NIGHT_FONT_30;
#endif
    lv_coord_t width = _lv_txt_get_width(txt, strlen(txt),  draw_dsc.font, draw_dsc.letter_space, LV_TXT_FLAG_CENTER);
    lv_canvas_draw_text(ext->canvas, offset_x + dsc->text_pos.x, offset_y + dsc->text_pos.y, width, &draw_dsc, txt, LV_LABEL_ALIGN_CENTER);
}

static bool dial_get_bg_switch(watch_dial_t * watch_dial)
{
    watch_element_t * element;
    watch_element_base_t ** base_node;
    _LV_LL_READ(watch_dial->element_ll, element) {
        _LV_LL_READ(element->element_dsc_ll, base_node) {
            watch_element_base_t * base = (watch_element_base_t *)*base_node;
            if(base->element_type == ELEMENT_TYPE_BG_SWITCH) {
                return true;
            }
        }
    }
    return false;
}

static bool dial_is_unchangeable_img(watch_img_type_t type)
{
    if(type == IMG_TYPE_TIME_CONNECTOR ||
            //type == IMG_TYPE_TIME_CENTER_DOT ||
            type == IMG_TYPE_DATE_CONNECTOR ||
            type == IMG_TYPE_CALORIE ||
            type == IMG_TYPE_STEP ||
            type == IMG_TYPE_DISTANCE ||
            type == IMG_TYPE_SLEEP_QUALITY ||
            type == IMG_TYPE_PRESSURE ||
            type == IMG_TYPE_HEART_RATE ||
            type == IMG_TYPE_WEATHER_UV ||
            type == IMG_TYPE_WEATHER_AQI ||
            type == IMG_TYPE_BLOOD_OXYGEN)
        return true;
    else
        return false;
}

static bool dial_is_unchangeable_label(watch_label_type_t type)
{
    if(type == LABEL_TYPE_TIME_CONNECTOR ||
            type == LABEL_TYPE_DATE_CONNECTOR ||
            type == LABEL_TYPE_CALORIE_KCAL ||
            type == LABEL_TYPE_STEP_STEPS ||
            type == LABEL_TYPE_DISTANCE_KM ||
            type == LABEL_TYPE_HEART_RATE_BPM)
        return true;
    else
        return false;
}

static void dial_get_element_pos(watch_element_type_t type, lv_point_t * pos)
{
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(dial_get_clock_cont());
    watch_dial_t * watch_dial = ext->watch_dial;
    watch_element_t * element;
    _LV_LL_READ(watch_dial->element_ll, element) {
        if(type == element->act_type) {
            pos->x = element->element_pos.x;
            pos->y = element->element_pos.y;
            break;
        }
    }
}

static void dial_update_canvas_label(watch_element_base_t * base)
{
    watch_element_label_dsc_t * label_dsc;
    hal_rtc_t tm;
    uint8_t len = 10;
    char infotxt[len];
    app_adaptor_weather_t weather;
    app_adaptor_pedometer_record_t record;
    app_adaptor_health_info_t health;
    lv_point_t pos;

    if(ELEMENT_TYPE_WEEK == base->element_type || ELEMENT_TYPE_DATE == base->element_type
            || ELEMENT_TYPE_TIME_DIGIT == base->element_type || ELEMENT_TYPE_AM_PM == base->element_type) {
        Hal_Rtc_Gettime(&tm);
    }
    if(ELEMENT_TYPE_WEATHER == base->element_type) {
        app_adaptor_get_weather_req(&weather);
    }
    if(ELEMENT_TYPE_STEP == base->element_type || ELEMENT_TYPE_DISTANCE == base->element_type || ELEMENT_TYPE_CALORIE == base->element_type) {
        app_adaptor_get_pedometer_info_req(&record);
    }
    if(ELEMENT_TYPE_HEART_RATE == base->element_type || ELEMENT_TYPE_SLEEP_QUALITY == base->element_type || ELEMENT_TYPE_BLOOD_OXYGEN == base->element_type
            || ELEMENT_TYPE_PRESSURE == base->element_type) {
        app_adaptor_get_health_info_req(&health);
    }

    dial_get_element_pos(base->element_type, &pos);
    _LV_LL_READ(base->label_ll, label_dsc) {
        switch(label_dsc->label_type) {
            case LABEL_TYPE_TIME_HOUR:
                snprintf(infotxt, len, "%.2d", tm.tm_hour);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_TIME_MIN:
                snprintf(infotxt, len, "%.2d", tm.tm_min);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_TIME_SEC:
                //snprintf(infotxt, len, "%.2d", tm.tm_sec);
                //dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_AM_PM: {
                if(tm.tm_hour >= 0 && tm.tm_hour <= 12)
                    snprintf(infotxt, len, "%s", "AM");
                else
                    snprintf(infotxt, len, "%s", "PM");
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            }
            case LABEL_TYPE_WEEK_EN: {
                char * weekstr[7] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
                snprintf(infotxt, len, "%s", (weekstr[tm.tm_wday]));
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            }
            case LABEL_TYPE_WEEK: {
                uint16_t weekstr_id[7] = {WATCH_TEXT_ID_SUNDAY, WATCH_TEXT_ID_MONDAY, WATCH_TEXT_ID_TUESDAY,
                                          WATCH_TEXT_ID_WEDNESDAY, WATCH_TEXT_ID_THURSDAY, WATCH_TEXT_ID_FRIDAY,
                                          WATCH_TEXT_ID_SATURDAY
                                         };
                snprintf(infotxt, len, "%s", (char *)lv_lang_get_text(weekstr_id[tm.tm_wday]));
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            }
            case LABEL_TYPE_DATE_YEAR:
                snprintf(infotxt, len, "%d", tm.tm_year);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_DATE_MONTH:
                snprintf(infotxt, len, "%.2d", tm.tm_mon);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_DATE_DAY:
                snprintf(infotxt, len, "%.2d", tm.tm_mday);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_MONTH: {
                char * monstr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
                                     "Aug", "Sept", "Oct", "Nov", "Dec"
                                    };
                snprintf(infotxt, len, "%s", monstr[tm.tm_mon - 1]);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            }
            case LABEL_TYPE_WEATHER_TEMP:
                if(weather.current_temperature < 0)
                    snprintf(infotxt, len, "-%d", abs(weather.current_temperature));
                else
                    snprintf(infotxt, len, "%d", weather.current_temperature);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_WEATHER_UV:
                snprintf(infotxt, len, "%.1f", (float)weather.uv);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_WEATHER_AQI:
                snprintf(infotxt, len, "%d", weather.aqi);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_STEP:
                snprintf(infotxt, len, "%.5d", record.step);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_BATTERY:
                snprintf(infotxt, len, "%d", Hal_Battery_Get_Status());
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_CALORIE:
                snprintf(infotxt, len, "%d", record.kcal);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_HEART_RATE:
                snprintf(infotxt, len, "%.3d", health.heartrate);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_DISTANCE:
                snprintf(infotxt, len, "%.1f", record.km);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_BLOOD_OXYGEN:
                snprintf(infotxt, len, "%d%%", health.bloodoxygen);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_PRESSURE:
                snprintf(infotxt, len, "%.3d", health.pressure);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            case LABEL_TYPE_SLEEP_QUALITY:
                snprintf(infotxt, len, "%d", health.sleep);
                dial_create_canvas_text(infotxt, label_dsc, pos.x, pos.y);
                break;
            default:
                break;
        }
    }
}

static void dial_update_canvas_img(watch_element_base_t * base)
{
    watch_element_img_dsc_t * img_dsc;
    app_adaptor_weather_t weather;
    app_adaptor_pedometer_record_t record;
    app_adaptor_health_info_t health;
    void * sub_img = NULL;
    int16_t angle = 0;
    hal_rtc_t tm;
    lv_point_t pos;

    if(ELEMENT_TYPE_WEEK == base->element_type || ELEMENT_TYPE_DATE == base->element_type || ELEMENT_TYPE_TIME_HAND == base->element_type
            || ELEMENT_TYPE_TIME_DIGIT == base->element_type || ELEMENT_TYPE_AM_PM == base->element_type) {
        Hal_Rtc_Gettime(&tm);
    }
    if(ELEMENT_TYPE_WEATHER == base->element_type) {
        app_adaptor_get_weather_req(&weather);
    }
    if(ELEMENT_TYPE_STEP == base->element_type || ELEMENT_TYPE_DISTANCE == base->element_type || ELEMENT_TYPE_CALORIE == base->element_type) {
        app_adaptor_get_pedometer_info_req(&record);
    }
    if(ELEMENT_TYPE_HEART_RATE == base->element_type || ELEMENT_TYPE_SLEEP_QUALITY == base->element_type || ELEMENT_TYPE_BLOOD_OXYGEN == base->element_type
            || ELEMENT_TYPE_PRESSURE == base->element_type) {
        app_adaptor_get_health_info_req(&health);
    }

    dial_get_element_pos(base->element_type, &pos);
    _LV_LL_READ(base->img_ll, img_dsc) {
        switch(img_dsc->img_type) {
            case IMG_TYPE_TIME_HOUR_HAND:
                angle = tm.tm_hour % 12 * 300 + tm.tm_min * 5;
                if(angle < 0) angle += 3600;
                sub_img = dial_get_sub_img(img_dsc, 0);
                dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_MIN_HAND:
                angle = tm.tm_min * 60;
                if(angle < 0) angle += 3600;
                sub_img = dial_get_sub_img(img_dsc, 0);
                dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_SEC_HAND:
                /* angle = tm.tm_sec * 60;
                if(angle < 0) angle += 3600;
                sub_img = dial_get_sub_img(img_dsc, 0);
                dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);*/
                break;
            case IMG_TYPE_TIME_HOUR_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_hour / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_HOUR_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_hour % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_MIN_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_min / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_MIN_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_min % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_SEC_TENS:
                /* sub_img = dial_get_sub_img(img_dsc, tm.tm_sec / 10);
                if(sub_img)
                dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);*/
                break;
            case IMG_TYPE_TIME_SEC_UNIT:
                /* sub_img = dial_get_sub_img(img_dsc, tm.tm_sec % 10);
                if(sub_img)
                dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);*/
                break;
            case IMG_TYPE_TIME_AM_PM:
                if(tm.tm_hour <= 12)
                    sub_img = dial_get_sub_img(img_dsc, 0);
                else
                    sub_img = dial_get_sub_img(img_dsc, 1);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_MON:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon % 13 - 1);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_YEAR_THOUSAND:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_year / 1000);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_YEAR_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, (tm.tm_year % 1000) / 100);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_YEAR_TENS:
                sub_img = dial_get_sub_img(img_dsc, (tm.tm_year % 100) / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_YEAR_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_year % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_MON_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_MON_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_DAY_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mday / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_DAY_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mday % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_WEEK_DIGIT:
                printf("%s: wday = %d\n", __FUNCTION__, tm.tm_wday);
                sub_img = dial_get_sub_img(img_dsc, tm.tm_wday % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_WEEK_HAND:
                angle = (tm.tm_wday - 6) % 7 * (3600 / 7);
                if(angle < 0) angle += 3600;
                sub_img = dial_get_sub_img(img_dsc, 0);
                dial_update_canvas(sub_img, angle, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
#if USE_LV_WATCH_PEDOMETER!= 0
            case IMG_TYPE_STEP_MYRI:
                sub_img = dial_get_sub_img(img_dsc, (record.step / 10000));
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_STEP_THOUSAND:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 10000) / 1000);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_STEP_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 1000) / 100);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_STEP_TENS:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 100) / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_STEP_UNIT:
                sub_img = dial_get_sub_img(img_dsc, record.step % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_STEP_PROGRESS:
                sub_img = dial_get_sub_img(img_dsc, ((record.step * 100) / pedometer_get_goalsteps()) / (100 / img_dsc->subimg->sub_img_cnt));
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
#endif
#if USE_LV_WATCH_HEART_RATE!= 0
            case IMG_TYPE_HEART_RATE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate / 100);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_HEART_RATE_TENS:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate % 100 / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_HEART_RATE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
#endif
            case IMG_TYPE_WEATHER:
                if(WATCH_WEATHER_ID_NO_INFO == weather.weather_id || WATCH_WEATHER_ID_OTHERS == weather.weather_id) {
                    sub_img = dial_get_sub_img(img_dsc, 0);
                } else {
                    sub_img = dial_get_sub_img(img_dsc, weather.weather_id + 1);
                }
                if(sub_img == NULL) sub_img = dial_get_sub_img(img_dsc, 0);
                dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TEMPERATURE_TENS:
                sub_img = dial_get_sub_img(img_dsc, abs(weather.current_temperature) / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TEMPERATURE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, abs(weather.current_temperature) % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_BATTERY:
                sub_img = dial_get_sub_img(img_dsc, Hal_Battery_Get_Status() / (100 / img_dsc->subimg->sub_img_cnt));
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_DISTANCE_TENS:
                sub_img = dial_get_sub_img(img_dsc, record.km / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_DISTANCE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, (int)record.km % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_DISTANCE_DECI: {
                float dis_km = record.km * 10;
                sub_img = dial_get_sub_img(img_dsc, ((int)dis_km) % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            }
            case IMG_TYPE_DISTANCE_PROGRESS: {
                float dis_pro = (record.km * 100) / 20;
                sub_img = dial_get_sub_img(img_dsc, ((int) dis_pro / (100 / img_dsc->subimg->sub_img_cnt)));
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            }
            case IMG_TYPE_CALORIE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, record.kcal / 100);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_CALORIE_TENS:
                sub_img = dial_get_sub_img(img_dsc, (record.kcal % 100) / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_CALORIE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, record.kcal % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_CALORIE_PROGRESS:
                sub_img = dial_get_sub_img(img_dsc, ((record.kcal * 100 / 1000) / (100 / img_dsc->subimg->sub_img_cnt)));
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_BLOOD_OXYGEN_TENS:
                sub_img = dial_get_sub_img(img_dsc, health.bloodoxygen / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_BLOOD_OXYGEN_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.bloodoxygen % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_SLEEP_QUALITY_VALUE:
                sub_img = dial_get_sub_img(img_dsc, health.sleep);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_PRESSURE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, health.pressure / 100);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_PRESSURE_TENS:
                sub_img = dial_get_sub_img(img_dsc, (health.pressure % 100) / 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_PRESSURE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.pressure % 10);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_PRESSURE_LEVEL:
                if(health.pressure >= PRESSURE_LEVEL_HIGH)
                    sub_img = dial_get_sub_img(img_dsc, 0);
                else if(health.pressure < PRESSURE_LEVEL_HIGH && health.pressure >= PRESSURE_LEVEL_MEDIUM)
                    sub_img = dial_get_sub_img(img_dsc, 1);
                else if(health.pressure < PRESSURE_LEVEL_MEDIUM && health.pressure >= PRESSURE_LEVEL_LOW)
                    sub_img = dial_get_sub_img(img_dsc, 2);
                else
                    sub_img = dial_get_sub_img(img_dsc, 3);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_TIME_CENTER_DOT:
                sub_img = dial_get_sub_img(img_dsc, 0);
                if(sub_img)
                    dial_update_canvas(sub_img, 0, pos.x + img_dsc->img_pos.x, pos.y + img_dsc->img_pos.y);
                break;
            case IMG_TYPE_BG:
                dial_clean_canvas(true);
                dial_update_all_element(dial_get_clock_cont());
                break;
            default:
                break;
        }
    }
}
#else

static void dial_update_img(watch_element_base_t * base)
{
    watch_element_img_dsc_t * img_dsc;
    app_adaptor_weather_t weather;
    app_adaptor_pedometer_record_t record;
    app_adaptor_health_info_t health;
    void * sub_img = NULL;
    int16_t angle;
    hal_rtc_t tm;

    if(ELEMENT_TYPE_WEEK == base->element_type || ELEMENT_TYPE_DATE == base->element_type || ELEMENT_TYPE_TIME_HAND == base->element_type
            || ELEMENT_TYPE_TIME_DIGIT == base->element_type || ELEMENT_TYPE_AM_PM == base->element_type) {
        Hal_Rtc_Gettime(&tm);
    }
    if(ELEMENT_TYPE_WEATHER == base->element_type) {
        app_adaptor_get_weather_req(&weather);
    }
    if(ELEMENT_TYPE_STEP == base->element_type || ELEMENT_TYPE_DISTANCE == base->element_type || ELEMENT_TYPE_CALORIE == base->element_type) {
        app_adaptor_get_pedometer_info_req(&record);
    }
    if(ELEMENT_TYPE_HEART_RATE == base->element_type || ELEMENT_TYPE_SLEEP_QUALITY == base->element_type || ELEMENT_TYPE_BLOOD_OXYGEN == base->element_type
            || ELEMENT_TYPE_PRESSURE == base->element_type) {
        app_adaptor_get_health_info_req(&health);
    }

    _LV_LL_READ(base->img_ll, img_dsc) {
        switch(img_dsc->img_type) {
            case IMG_TYPE_TIME_HOUR_HAND:
                angle = tm.tm_hour % 12 * 300 + tm.tm_min * 5;
                if(angle < 0) angle += 3600;
                lv_img_set_angle(img_dsc->img_obj, angle);
                break;
            case IMG_TYPE_TIME_MIN_HAND:
                angle = tm.tm_min * 60;
                if(angle < 0) angle += 3600;
                lv_img_set_angle(img_dsc->img_obj, angle);
                break;
            case IMG_TYPE_TIME_SEC_HAND:
                angle = tm.tm_sec * 60;
                if(angle < 0) angle += 3600;
                lv_img_set_angle(img_dsc->img_obj, angle);
                break;
            case IMG_TYPE_TIME_HOUR_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_hour / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_HOUR_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_hour % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_MIN_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_min / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_MIN_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_min % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_SEC_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_sec / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_SEC_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_sec % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TIME_AM_PM:
                if(tm.tm_hour <= 12)
                    sub_img = dial_get_sub_img(img_dsc, 0);
                else
                    sub_img = dial_get_sub_img(img_dsc, 1);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_MON:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon % 13 - 1);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_YEAR_THOUSAND:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_year / 1000);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_YEAR_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, (tm.tm_year % 1000) / 100);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_YEAR_TENS:
                sub_img = dial_get_sub_img(img_dsc, (tm.tm_year % 100) / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_YEAR_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_year % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_MON_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_MON_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mon % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_DAY_TENS:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mday / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_DAY_UNIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_mday % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_WEEK_DIGIT:
                sub_img = dial_get_sub_img(img_dsc, tm.tm_wday % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_WEEK_HAND:
                printf("%s: wday = %d\n", __FUNCTION__, tm.tm_wday);
                angle = (tm.tm_wday - 6) % 7 * (3600 / 7);
                if(angle < 0) angle += 3600;
                lv_img_set_angle(img_dsc->img_obj, angle);
                break;
#if USE_LV_WATCH_PEDOMETER!= 0
            case IMG_TYPE_STEP_MYRI:
                sub_img = dial_get_sub_img(img_dsc, (record.step / 10000));
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_STEP_THOUSAND:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 10000) / 1000);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_STEP_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 1000) / 100);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_STEP_TENS:
                sub_img = dial_get_sub_img(img_dsc, (record.step % 100) / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_STEP_UNIT:
                sub_img = dial_get_sub_img(img_dsc, record.step % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_STEP_PROGRESS:
                sub_img = dial_get_sub_img(img_dsc, ((record.step * 100) / pedometer_get_goalsteps()) / (100 / img_dsc->subimg->sub_img_cnt));
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
#endif
#if USE_LV_WATCH_HEART_RATE!= 0
            case IMG_TYPE_HEART_RATE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate / 100);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_HEART_RATE_TENS:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate % 100 / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_HEART_RATE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.heartrate % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
#endif
            case IMG_TYPE_WEATHER:
                printf("%s: weather_id = %d\n", __FUNCTION__, weather.weather_id);
                if(WATCH_WEATHER_ID_NO_INFO == weather.weather_id || WATCH_WEATHER_ID_OTHERS == weather.weather_id) {
                    sub_img = dial_get_sub_img(img_dsc, 0);
                } else {
                    sub_img = dial_get_sub_img(img_dsc, weather.weather_id + 1);
                }
                if(sub_img == NULL) sub_img = dial_get_sub_img(img_dsc, 0);
                lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TEMPERATURE_TENS:
                printf("%s: cur temp = %d\n", __FUNCTION__, abs(weather.current_temperature));
                sub_img = dial_get_sub_img(img_dsc, abs(weather.current_temperature) / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TEMPERATURE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, abs(weather.current_temperature) % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_TEMPERATURE_MINUS:
                if(weather.current_temperature < 0) {
                    lv_obj_set_hidden(img_dsc->img_obj, false);
                } else {
                    lv_obj_set_hidden(img_dsc->img_obj, true);
                }
                break;
            case IMG_TYPE_BATTERY:
                sub_img = dial_get_sub_img(img_dsc, Hal_Battery_Get_Status() / (100 / img_dsc->subimg->sub_img_cnt));
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_DISTANCE_TENS:
                sub_img = dial_get_sub_img(img_dsc, record.km / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_DISTANCE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, (int)record.km % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_DISTANCE_DECI: {
                float dis_km = record.km * 10;
                sub_img = dial_get_sub_img(img_dsc, ((int)dis_km) % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            }
            case IMG_TYPE_DISTANCE_PROGRESS: {
                float dis_pro = (record.km * 100) / 20;
                sub_img = dial_get_sub_img(img_dsc, ((int) dis_pro / (100 / img_dsc->subimg->sub_img_cnt)));
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            }
            case IMG_TYPE_CALORIE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, record.kcal / 100);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_CALORIE_TENS:
                sub_img = dial_get_sub_img(img_dsc, (record.kcal % 100) / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_CALORIE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, record.kcal % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_CALORIE_PROGRESS:
                sub_img = dial_get_sub_img(img_dsc, ((record.kcal * 100 / 1000) / (100 / img_dsc->subimg->sub_img_cnt)));
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_BLOOD_OXYGEN_TENS:
                sub_img = dial_get_sub_img(img_dsc, health.bloodoxygen / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_BLOOD_OXYGEN_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.bloodoxygen % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_SLEEP_QUALITY_VALUE:
                sub_img = dial_get_sub_img(img_dsc, health.sleep);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_PRESSURE_HUNDRED:
                sub_img = dial_get_sub_img(img_dsc, health.pressure / 100);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_PRESSURE_TENS:
                sub_img = dial_get_sub_img(img_dsc, (health.pressure % 100) / 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_PRESSURE_UNIT:
                sub_img = dial_get_sub_img(img_dsc, health.pressure % 10);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_PRESSURE_LEVEL:
                if(health.pressure >= PRESSURE_LEVEL_HIGH)
                    sub_img = dial_get_sub_img(img_dsc, 0);
                else if(health.pressure < PRESSURE_LEVEL_HIGH && health.pressure >= PRESSURE_LEVEL_MEDIUM)
                    sub_img = dial_get_sub_img(img_dsc, 1);
                else if(health.pressure < PRESSURE_LEVEL_MEDIUM && health.pressure >= PRESSURE_LEVEL_LOW)
                    sub_img = dial_get_sub_img(img_dsc, 2);
                else
                    sub_img = dial_get_sub_img(img_dsc, 3);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            case IMG_TYPE_BG:
                g_bg_index = g_bg_index + 1;
                if(g_bg_index == img_dsc->subimg->sub_img_cnt)
                    g_bg_index = 0;
                sub_img = dial_get_sub_img(img_dsc, g_bg_index);
                if(sub_img)
                    lv_img_set_src(img_dsc->img_obj, sub_img);
                break;
            default:
                break;
        }
    }
}

static void dial_update_label(watch_element_base_t * base)
{
    watch_element_label_dsc_t * label_dsc;
    hal_rtc_t tm;
    uint8_t len = 10;
    char infotxt[len];
    app_adaptor_weather_t weather;
    app_adaptor_pedometer_record_t record;
    app_adaptor_health_info_t health;

    if(ELEMENT_TYPE_WEEK == base->element_type || ELEMENT_TYPE_DATE == base->element_type
            || ELEMENT_TYPE_TIME_DIGIT == base->element_type || ELEMENT_TYPE_AM_PM == base->element_type) {
        Hal_Rtc_Gettime(&tm);
    }
    if(ELEMENT_TYPE_WEATHER == base->element_type) {
        app_adaptor_get_weather_req(&weather);
    }
    if(ELEMENT_TYPE_STEP == base->element_type || ELEMENT_TYPE_DISTANCE == base->element_type || ELEMENT_TYPE_CALORIE == base->element_type) {
        app_adaptor_get_pedometer_info_req(&record);
    }
    if(ELEMENT_TYPE_HEART_RATE == base->element_type || ELEMENT_TYPE_SLEEP_QUALITY == base->element_type || ELEMENT_TYPE_BLOOD_OXYGEN == base->element_type
            || ELEMENT_TYPE_PRESSURE == base->element_type) {
        app_adaptor_get_health_info_req(&health);
    }

    _LV_LL_READ(base->label_ll, label_dsc) {
        switch(label_dsc->label_type) {
            case LABEL_TYPE_TIME_HOUR:
                snprintf(infotxt, len, "%.2d", tm.tm_hour);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_TIME_MIN:
                snprintf(infotxt, len, "%.2d", tm.tm_min);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_TIME_SEC:
                snprintf(infotxt, len, "%.2d", tm.tm_sec);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_AM_PM: {
                if(tm.tm_hour >= 0 && tm.tm_hour <= 12)
                    snprintf(infotxt, len, "%s", "AM");
                else
                    snprintf(infotxt, len, "%s", "PM");
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            }
            case LABEL_TYPE_WEEK_EN: {
                char * weekstr[7] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
                snprintf(infotxt, len, "%s", (weekstr[tm.tm_wday]));
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            }
            case LABEL_TYPE_WEEK: {
                uint16_t weekstr_id[7] = {WATCH_TEXT_ID_SUNDAY, WATCH_TEXT_ID_MONDAY, WATCH_TEXT_ID_TUESDAY,
                                          WATCH_TEXT_ID_WEDNESDAY, WATCH_TEXT_ID_THURSDAY, WATCH_TEXT_ID_FRIDAY,
                                          WATCH_TEXT_ID_SATURDAY
                                         };
                snprintf(infotxt, len, "%s", (char *)lv_lang_get_text(weekstr_id[tm.tm_wday]));
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            }
            case LABEL_TYPE_DATE_YEAR:
                snprintf(infotxt, len, "%d", tm.tm_year);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_DATE_MONTH:
                snprintf(infotxt, len, "%.2d", tm.tm_mon);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_DATE_DAY:
                snprintf(infotxt, len, "%.2d", tm.tm_mday);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_MONTH: {
                char * monstr[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
                                     "Aug", "Sept", "Oct", "Nov", "Dec"
                                    };
                snprintf(infotxt, len, "%s", monstr[tm.tm_mon - 1]);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            }
            case LABEL_TYPE_WEATHER_TEMP:
                if(weather.current_temperature < 0)
                    snprintf(infotxt, len, "-%d", abs(weather.current_temperature));
                else
                    snprintf(infotxt, len, "%d", weather.current_temperature);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_WEATHER_UV:
                snprintf(infotxt, len, "%.1f", (float)weather.uv);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_WEATHER_AQI:
                snprintf(infotxt, len, "%d", weather.aqi);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_STEP:
                snprintf(infotxt, len, "%.5d", record.step);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_BATTERY:
                snprintf(infotxt, len, "%d", Hal_Battery_Get_Status());
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_CALORIE:
                snprintf(infotxt, len, "%d", record.kcal);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_HEART_RATE:
                snprintf(infotxt, len, "%.3d", health.heartrate);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_DISTANCE:
                snprintf(infotxt, len, "%.1f", record.km);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;;
            case LABEL_TYPE_BLOOD_OXYGEN:
                snprintf(infotxt, len, "%d%%", health.bloodoxygen);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_PRESSURE:
                snprintf(infotxt, len, "%.3d", health.pressure);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            case LABEL_TYPE_SLEEP_QUALITY:
                snprintf(infotxt, len, "%d", health.sleep);
                lv_label_set_text(label_dsc->label_obj, infotxt);
                break;
            default:
                break;
        }
    }
}
#endif

static void dial_update_bar(watch_element_base_t * base)
{
#if USE_LV_WATCH_PEDOMETER!= 0
    switch(base->element_type) {
        case ELEMENT_TYPE_STEP: {
            float delta = (float)pedometer_get_steps() / pedometer_get_goalsteps();
            if(delta > 1) delta = 1;
            int16_t val = delta * 360 - 90 - 1;
            printf("%s: step val = %d\n", __FUNCTION__, val);
            lv_arc_set_end_angle(base->bar_dsc.bar_obj, val);
            break;
        }
        case ELEMENT_TYPE_BATTERY:
        case ELEMENT_TYPE_DISTANCE:
            break;
    }
#endif
}

void dial_start_app(lv_point_t * point)
{
    lv_watch_png_cache_all_free();
    lv_clock_ext_t * ext = lv_obj_get_ext_attr(dial_get_clock_cont());
    watch_element_t * element;
    watch_element_base_t ** base_node;
    watch_element_base_t * base;
    uint8_t type;
    bool find = false;
    _LV_LL_READ(ext->watch_dial->element_ll, element) {
        _LV_LL_READ(element->element_dsc_ll, base_node) {
            base = (watch_element_base_t *)*base_node;
            if(element->act_type == base->element_type
                    && point->x > element->element_pos.x && point->y > element->element_pos.y) {
                type = base->element_type;
                find = true;
                break;
            }
        }
        if(find) break;
    }
    if(!find) {
        printf("%s: Can't find app to start!\n", __FUNCTION__);
        return;
    }
    printf("%s: type = %d\n", __FUNCTION__, type);
    switch(type) {
        case ELEMENT_TYPE_TIME_DIGIT:
            // setting_date_time_create(NULL);
            break;
        case ELEMENT_TYPE_WEEK:
        case ELEMENT_TYPE_DATE:
            //calendar_create(NULL);
            break;
        case ELEMENT_TYPE_WEATHER:
            break;
        case ELEMENT_TYPE_STEP:
        case ELEMENT_TYPE_DISTANCE:
        case ELEMENT_TYPE_CALORIE:
            //sport_create(NULL);
            break;
        case ELEMENT_TYPE_HEART_RATE:
            break;
        case ELEMENT_TYPE_BATTERY:
        case ELEMENT_TYPE_SLEEP_QUALITY:
        case ELEMENT_TYPE_PRESSURE:
        case ELEMENT_TYPE_BLOOD_OXYGEN:
            break;
    }
}

static void dial_element_setting_btn_event_cb(lv_obj_t * obj, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    watch_element_base_t ** base_node;
    watch_element_t * element = (watch_element_t *)lv_obj_get_user_data(obj).user_data;
    char * txt = (char *)lv_checkbox_get_text(obj);
#if DIAL_USE_CANVAS
    lv_obj_t * bg_img = lv_obj_get_parent(lv_obj_get_parent(lv_obj_get_parent(lv_obj_get_parent(obj))));
#else
    lv_obj_t * cont = dial_get_clock_cont();
    lv_obj_t * bg_img = lv_obj_get_child(cont, NULL);
#endif
    _LV_LL_READ(element->element_dsc_ll, base_node) {
        watch_element_base_t * base = (watch_element_base_t *)*base_node;
        if(memcmp(base->element_name, txt, strlen(txt)) == 0) {
            element->act_type = base->element_type;
            dial_save_act_element(element->element_pos, element->act_type);
            break;
        }
    }
    lv_obj_clean(bg_img);
    dial_add_configurable_element(bg_img);
}

static void dial_element_setting_event_cb(lv_obj_t * obj, lv_event_t event)
{
    if(LV_EVENT_CLICKED != event) return;
    printf("%s: create element list\n", __FUNCTION__);
    watch_element_base_t ** base_node;
    watch_element_t * element = (watch_element_t *)lv_obj_get_user_data(obj).user_data;
    lv_obj_t * par = lv_obj_get_parent(obj);
    lv_obj_t * custom_list = lv_list_create(par, NULL);
    lv_obj_set_size(custom_list, lv_obj_get_width(par), lv_obj_get_height(par));
    lv_obj_align(custom_list, NULL, LV_ALIGN_CENTER, 0,  0);
    lv_obj_set_style_local_bg_color(custom_list, LV_LIST_PART_BG, LV_STATE_DEFAULT, LV_COLOR_BLACK);
    lv_obj_set_style_local_pad_top(custom_list, LV_LIST_PART_SCROLLABLE, LV_STATE_DEFAULT, 70);
    lv_obj_set_style_local_pad_inner(custom_list, LV_LIST_PART_SCROLLABLE, LV_STATE_DEFAULT, 30);
    lv_obj_set_style_local_pad_left(custom_list, LV_LIST_PART_SCROLLABLE, LV_STATE_DEFAULT, 80);
    lv_obj_set_style_local_pad_right(custom_list, LV_LIST_PART_SCROLLABLE, LV_STATE_DEFAULT, 80);
    lv_obj_t * btn;
    lv_obj_t * cb;
    _LV_LL_READ(element->element_dsc_ll, base_node) {
        watch_element_base_t * base = (watch_element_base_t *)*base_node;
        btn = lv_list_add_btn(custom_list, NULL, NULL);
        cb = lv_checkbox_create(btn, NULL);
        lv_checkbox_set_text(cb, base->element_name);
        lv_obj_clean_style_list(cb, LV_CHECKBOX_PART_BULLET);
        lv_obj_add_style(cb, LV_CHECKBOX_PART_BG, &lv_watch_font30);
        lv_obj_add_style(cb, LV_CHECKBOX_PART_BULLET, &lv_watch_cb_styles);
        lv_obj_set_event_cb(cb, dial_element_setting_btn_event_cb);
        lv_watch_set_free_ptr(cb, element);
        if(base->element_type == element->act_type)
            lv_checkbox_set_checked(cb, true);
        else
            lv_checkbox_set_checked(cb, false);
    }
}

static void dial_save_act_element(lv_point_t pos, uint8_t type)
{
    nv_watch_launcher_t dial_info;
    uint8_t i = 0;
    UI_NV_Read_Req(NV_SECTION_UI_LAUNCHER, 0, sizeof(nv_watch_launcher_t), (uint8_t *)&dial_info);
    for(i = 0; i < NV_DIAL_MAX_ELEMENT_CNT; i++) {
        if(dial_info.element[i].pos.x == pos.x && dial_info.element[i].pos.y == pos.y) {
            dial_info.element[i].act_type = type;
            break;
        }
    }
    UI_NV_Write_Req(NV_SECTION_UI_LAUNCHER, 0, sizeof(nv_watch_launcher_t), (uint8_t *)&dial_info);
}

static void dial_get_act_element(watch_element_t * element)
{
    nv_watch_launcher_t dial_info;
    uint8_t i = 0;
    UI_NV_Read_Req(NV_SECTION_UI_LAUNCHER, 0, sizeof(nv_watch_launcher_t), (uint8_t *)&dial_info);
    for(i = 0; i < NV_DIAL_MAX_ELEMENT_CNT; i++) {
        if(dial_info.element[i].pos.x == element->element_pos.x
                && dial_info.element[i].pos.y == element->element_pos.y) {
            element->act_type = dial_info.element[i].act_type;
            break;
        }
    }
}

static void * dial_get_sub_img(watch_element_img_dsc_t * img_dsc, uint8_t index)
{
    void * sub_img;
    uint8_t i = 0;

    _LV_LL_READ(img_dsc->subimg->sub_img_ll, sub_img) {
        if(i++ == index)
            return sub_img;
    }
    return NULL;
}

#endif /*USE_LV_WATCH_DIAL*/
